package htw.stack;

import java.util.*;
import htw.stack.*;

/**
 * Class Stack implements abstrackt Class AbstractStack
 * 
 * @author Andreas Dier, Steffen Schuhmann 
 * @version 1.0
 */
public class Stack implements AbstractStack{

	private static final int MINSIZE       = 5;
	private static final int MAXSIZE	   = 50;
	private static final int CHANGESIZE    = 25;
	private static final int STANDARTSIZE  = 25;
	
	private Object[]  stack		 = null;
	private int       stackSize  = 0;
	private int 	  size 		 = 0;
	
	/**
	 * Constructor of the Class 
	 */
	public Stack(Object o){
		this.stackSize  = STANDARTSIZE;
		this.stack 		= new Object[stackSize];
		
		push(o);
	}
	
	/**
	 * pushs a Object to the stack
	 * 
	 * @param o Object to push
	 */
	public void push(Object o){
		if( freespace() <= MINSIZE )
		{
			Object[] newStack = new Object[stackSize() + CHANGESIZE];
			for( int i = 0; i <= stack.length; i++ )
			{
				newStack[i] = stack[i];
			}
			stack = newStack;
			this.stackSize = stackSize() + CHANGESIZE;
		}
		stack[size()+1] = o;
		incSize();
	}
	
	/**
	 * increments the size
	 */
	private void incSize(){
		this.size++;
	}
	
	/**
	 * decrements the size
	 */
	private void decSize(){
		this.size--;
	}
	
	/**
	 * pushs an int to the stack
	 * 
	 * @param i int to push
	 */
	public void push(int i){
		push((Integer) i);		
	}
	
	/**
	 * pushs boolean to the stack
	 * 
	 * @param b boolean to push
	 */
	public void push(boolean b){
		push((Boolean) b);		
	}
	
	/**
	 * pushs char to the stack
	 * 
	 * @param c char to push
	 */
	public void push(char c){
		push((Character)  c );		
	}
	
	/**
	 * pushs long to the stack
	 * 
	 * @param l long to push
	 */
	public void push(long l){
		push((Long) l);		
	}
	
	/**
	 * pushs double to the stack
	 * 
	 * @param d double to push
	 */
	public void push(double d){
		push((Double) d);		
	}
	
	/**
	 * pushs float to the stack
	 * 
	 * @param f float to push
	 */
	public void push(float f){
		push((Float) f);		
	}
	
	/**
	 * pushs short to the stack
	 * 
	 * @param short to push
	 */
	public void push(short s){
		push((Short) s);		
	}
	
	/**
	 * pops an object from the stack
	 * 
	 * @return returns the Object that was poped
	 */
	public Object pop(){
		Object oldObject;
		if( freespace() >= MAXSIZE )
		{
			Object[] newStack = new Object[stackSize() - CHANGESIZE];
			for( int i = 0; i <= stack.length; i++ )
			{
				newStack[i] = stack[i];
			}
			stack = newStack;
			this.stackSize = stackSize() - CHANGESIZE;
		}
		
		oldObject = stack[size()];
		decSize();		
		return oldObject;
	}
	
	/**
	 * return the stackSize
	 * 
	 * @return returns the stackSize
	 */
	public int stackSize(){
		return this.stackSize;
	}
	
	/**
	 * return the size
	 * 
	 * @return returns the size
	 */
	public int size(){
		return this.size;
	}
	
	/**
	 * return the freespace of the stack
	 * 
	 * @return returns freespace of the stack
	 */
	public int freespace(){
		return (stackSize() - size() );
	}


}